# /code/crawler.py
import aiohttp
import asyncio
import pandas as pd
from code.logger_config import logger
from code.config import UserTreeURLList, USERAGENT
from code.utils import load_cookie, extract_json_from_html, extract_gender_position
from code.db_ops import insert_into_staff, get_serving_staff_data, get_retired_staff_data, update_staff_updated_at, get_staff_with_unknown_gender_or_position, update_staff_gender_position
import os
import datetime


async def fetch_and_process(session, url, name, max_retries=3):
    """获取URL内容并处理，支持重试"""
    for attempt in range(max_retries):
        try:
            async with session.get(url) as response:
                if response.status == 200:
                    content = await response.text()
                    return (name, content)
                else:
                    logger.warning(f"尝试 {attempt + 1}/{max_retries}：{name} 返回状态码 {response.status}")
        except (aiohttp.ClientError, asyncio.TimeoutError) as e:
            logger.error(f"尝试 {attempt + 1}/{max_retries}：{name} 请求出错: {str(e)}")

        if attempt < max_retries - 1:
            await asyncio.sleep(2 ** attempt)

    logger.error(f"所有尝试失败：{name}")
    return (name, None)


async def user_tree_monitor(browser):
    """监控用户树并更新数据库"""
    if os.getenv('DEBUG_MODE') == 'True':
        logger.debug("UserTreeMonitor =>")

    # 预加载数据1: staff表中serving=true的数据
    serving_data = await asyncio.to_thread(get_serving_staff_data)
    serving_df = pd.DataFrame(serving_data, columns=['user_id', 'online_status'])
    serving_df.set_index('user_id', inplace=True)
    logger.info(f"预加载serving_staff数据: {len(serving_df)}条记录")

    if os.getenv('DEBUG_MODE') == 'True':
        print("预加载数据1 (serving_staff):")
        print(serving_df.to_string())

    # 预加载数据2: staff表中serving=false的数据
    retired_data = await asyncio.to_thread(get_retired_staff_data)
    retired_df = pd.DataFrame(retired_data, columns=['user_id', 'online_status'])
    retired_df.set_index('user_id', inplace=True)
    logger.info(f"预加载retired_staff数据: {len(retired_df)}条记录")

    if os.getenv('DEBUG_MODE') == 'True':
        print("预加载数据2 (retired_staff):")
        print(retired_df.to_string())

    loadedCookieList = await load_cookie()
    cookies_dict = {cookie['name']: cookie['value'] for cookie in loadedCookieList}

    timeout = aiohttp.ClientTimeout(total=120)
    connector = aiohttp.TCPConnector(limit=1)

    async with aiohttp.ClientSession(
            cookies=cookies_dict,
            connector=connector,
            timeout=timeout,
            headers={'User-Agent': USERAGENT}
    ) as session:
        tasks = []
        for EACH_USER_TREE in UserTreeURLList:
            USER_TREE_Name = EACH_USER_TREE[0]
            USER_TREE_URL = "".join((os.getenv('OA_HOST_URL'), EACH_USER_TREE[1]))

            if os.getenv('DEBUG_MODE') == 'True':
                logger.info(f"准备获取：{USER_TREE_Name}")
                logger.info(f"URL：{USER_TREE_URL}")

            task = asyncio.create_task(
                fetch_and_process(session, USER_TREE_URL, USER_TREE_Name)
            )
            tasks.append(task)

        results = await asyncio.gather(*tasks, return_exceptions=True)
        for result in results:
            if isinstance(result, Exception):
                logger.error(f"请求出错: {str(result)}")
            elif result:
                USER_TREE_Name, content = result
                if content:
                    UserTreeContent = extract_json_from_html(content)
                    if os.getenv('DEBUG_MODE') == 'True':
                        logger.success(f"成功处理：{USER_TREE_Name}")
                        # print("=>=>")
                        # print(USER_TREE_Name)
                        # print(UserTreeContent)

                    for user in UserTreeContent:
                        if 'user_id' in user and 'title' in user:
                            # 合并跳过条件：非数字ID、管理员用户、维修用户
                            if (not user['user_id'].isdigit() or
                                    "管理员" in user['title'] or
                                    "维修" in user['title']):

                                # 根据具体原因生成日志消息
                                if not user['user_id'].isdigit():
                                    reason = "非数字用户ID"
                                elif "管理员" in user['title']:
                                    reason = "管理员用户"
                                else:
                                    reason = "维修用户"

                                logger.warning(f"跳过{reason}: {user['title']} (ID: {user['user_id']})")
                                continue

                            user_id = int(user['user_id'])
                            dept_id = int(user.get('dept_id', 0))
                            online_status = user.get('online', False)
                            name = user['title']

                            # 情况1: 新入职员工
                            if user_id not in serving_df.index and user_id not in retired_df.index:
                                success = insert_into_staff(
                                    user_id=user_id,
                                    name=name,
                                    dept_id=dept_id,
                                    online_status=online_status,
                                    serving=True
                                )
                                if success:
                                    logger.info(
                                        f"新入职员工: {name} (ID: {user_id}, 部门: {dept_id}, 在线状态: {online_status})")
                                else:
                                    logger.warning(f"新员工写入失败: {name} (ID: {user_id})")

                            # 情况2: 在职员工
                            elif user_id in serving_df.index and user_id not in retired_df.index:
                                db_online_status = serving_df.loc[user_id, 'online_status'] == 'true'
                                current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')

                                # 情况2a: 用户在线但数据库记录不在线
                                if online_status and not db_online_status:
                                    success = insert_into_staff(
                                        user_id=user_id,
                                        name=name,
                                        dept_id=dept_id,
                                        online_status=online_status,
                                        serving=True,
                                        latest_login=current_time
                                    )
                                    if success:
                                        logger.info(f"在职员工上线: {name} (ID: {user_id}, 时间: {current_time})")

                                # 情况2b: 用户在线且数据库记录在线
                                elif online_status and db_online_status:
                                    success = insert_into_staff(
                                        user_id=user_id,
                                        name=name,
                                        dept_id=dept_id,
                                        online_status=online_status,
                                        serving=True,
                                        latest_login=current_time
                                    )
                                    if success:
                                        logger.info(f"在职员工活跃更新: {name} (ID: {user_id}, 时间: {current_time})")

                                # 情况2c: 用户不在线但数据库记录在线
                                elif not online_status and db_online_status:
                                    success = insert_into_staff(
                                        user_id=user_id,
                                        name=name,
                                        dept_id=dept_id,
                                        online_status=online_status,
                                        serving=True
                                    )
                                    if success:
                                        logger.info(f"在职员工下线: {name} (ID: {user_id})")

                            # 情况3: 退休员工
                            elif user_id not in serving_df.index and user_id in retired_df.index:
                                current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                                success = update_staff_updated_at(user_id, current_time)
                                if success:
                                    logger.info(f"退休员工更新: {name} (ID: {user_id}, 时间: {current_time})")
                                else:
                                    logger.warning(f"退休员工更新失败: {name} (ID: {user_id})")
                        else:
                            missing_fields = []
                            if 'user_id' not in user: missing_fields.append('user_id')
                            if 'title' not in user: missing_fields.append('title')
                            logger.warning(f"跳过用户记录，缺少必要字段: {', '.join(missing_fields)}")
                else:
                    logger.error(f"获取失败：{USER_TREE_Name}")

    logger.debug("UserTreeMonitor <=")


async def fetch_page_with_http(url, max_retries=3):
    """使用HTTP获取页面内容（适用于不需要JS分析的页面）"""

    loadedCookieList = await load_cookie()
    cookies_dict = {cookie['name']: cookie['value'] for cookie in loadedCookieList}

    timeout = aiohttp.ClientTimeout(total=30)
    connector = aiohttp.TCPConnector(limit=1)

    for attempt in range(max_retries):
        try:
            async with aiohttp.ClientSession(
                    cookies=cookies_dict,
                    connector=connector,
                    timeout=timeout,
                    headers={'User-Agent': USERAGENT}
            ) as session:
                async with session.get(url) as response:
                    if response.status == 200:
                        content = await response.text()
                        if os.getenv('DEBUG_MODE') == 'True':
                            logger.success(f"成功获取页面: {url}")
                        return content
                    else:
                        logger.warning(f"尝试 {attempt + 1}/{max_retries}：返回状态码 {response.status}")
        except (aiohttp.ClientError, asyncio.TimeoutError) as e:
            logger.error(f"尝试 {attempt + 1}/{max_retries}：请求出错: {str(e)}")

        if attempt < max_retries - 1:
            await asyncio.sleep(2 ** attempt)

    logger.error(f"所有尝试失败：{url}")
    return None


async def process_unknown_gender_position():
    """处理未知性别/职位的员工数据"""
    # 获取未知性别/职位的员工ID
    user_ids = await asyncio.to_thread(get_staff_with_unknown_gender_or_position)

    # 创建DataFrame并打印
    df = pd.DataFrame(user_ids, columns=['user_id'])
    print("未知性别/职位的员工ID:")
    print(df)

    # 使用信号量限制并发数为3
    semaphore = asyncio.Semaphore(3)

    async def process_user(user_id):
        async with semaphore:
            result = await get_gender_and_position(user_id)
            if result:
                # 更新数据库
                await asyncio.to_thread(
                    update_staff_gender_position,
                    user_id,
                    result['gender'],
                    result['position']
                )
                logger.info(f"已更新员工 {user_id}: 性别={result['gender']}, 职位={result['position']}")

    # 创建并运行所有任务
    tasks = [process_user(user_id) for user_id in user_ids]
    await asyncio.gather(*tasks)


async def get_gender_and_position(user_id):
    """测试不需要JS分析的页面"""
    test_url = f"http://172.18.0.17/general/ipanel/user/user_info.php?&USER_ID={user_id}"
    logger.info(f"HTTP获取页面: {test_url}")

    content = await fetch_page_with_http(test_url)
    if content:
        # 保存html
        with open("http_content.html", "w", encoding="utf-8") as f:
            f.write(content)

        extracted_by_js = extract_gender_position(content)
        logger.info(extracted_by_js)
        return extracted_by_js  # 返回提取结果
    else:
        logger.error("JS匹配失败")
        return {'gender': '未知', 'position': '未知'}